package mge
{
  import flash.display.DisplayObject;
  import flash.display.DisplayObjectContainer;
  import flash.display.Loader;
  import flash.display.MovieClip;
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.net.URLRequest;
  import flash.system.LoaderContext;
  import flash.text.TextField;
  
  // import graphics.Vec3;

  /**
  * @todo Function to recursively find a child in a display object. 
  * */
  public class Utils
  {
    public function Utils()
    {
    }
    
    public static function stopChildrens(mc:DisplayObjectContainer):void
    {
      for (var i:int = 0; i < mc.numChildren; i++)
      {
        var cmc:MovieClip = mc.getChildAt(i) as MovieClip;
        if (cmc)
        {
          cmc.stop();
          stopChildrens(mc.getChildAt(i) as Sprite);
        }        
      }      
    }
    
    /**
    * @param c: range [0...1]
    * @return value between a and b depending on c.
    * */
    public static function interpolate(a:Number, b:Number, c:Number):Number
    {
      return (b-a) * c + a;
    }
    
    /*
    public static function interpolateVec3(a:Vec3, b:Vec3, c:Number):Vec3
    {
      b.sub(a);
      b.scale(c);
      b.add(a);
      return b;
    }*/
    
    /**
    * Given values a, b and c, returns normalized interpolated value.
    * constrains:
    * --> a < b
    * --> c is a number between a and b.
    * */
    public static function interpolateInv(a:Number, b:Number, c:Number):Number
    {
      if (a >= b/* || c < a || c > b*/) throw new Error("Invalid input");
      if (c < a) c = a;
      if (c > b) c = b;
      return (c-a) / (b-a);
    }
    
    public static function safeRemoveChild(parent:DisplayObjectContainer, child:DisplayObject):void
    {
      if (isChild(child, parent))
      {
        parent.removeChild(child);
      }
    }
    
    public static function isChild(child:DisplayObject, parent:DisplayObjectContainer):Boolean
    {
      if (!parent || !child) return false;
      for (var i:int = 0; i < parent.numChildren; i++)
        if (parent.getChildAt(i) == child)
          return true;
          
      return false;
    }
    
    public static function removeAllChilds(displayObject:DisplayObjectContainer):void
    {
      if (!displayObject) return;
      while (displayObject.numChildren)
        displayObject.removeChildAt(0);
    }
    
    public static function loadImage(url:String, listener:Function):void  
    {  
      if (!url.length)
      {
        trace("Warning, void url");
        return;
      }
      var loader:Loader = new Loader;  
      loader.contentLoaderInfo.addEventListener(Event.COMPLETE, listener);
      var context:LoaderContext = new LoaderContext(true);  
      loader.load(new URLRequest(url), context);  
    }
    
    public static function removeBreakLines(st:String):String
    {
      while (st.search("\n") != -1)
      {
        // New line found
        var idx:int = st.search("\n");
        
        // Lets remove white spaces at the begining of the new line
        var spaceIdx:int = idx+1;
        while (st.substr(spaceIdx, 1) == " ")
        {
          spaceIdx++;
        }
        if (st.substr(spaceIdx, 1) == "<" && spaceIdx > idx+1)
        {
          // Place space required befor tag.
          spaceIdx--;
        }
        else if ( (st.substr(spaceIdx, 1) != ".") &&
                  (st.substr(spaceIdx, 1) != ",") &&
                  (st.substr(spaceIdx, 1) != "?") &&
                  (spaceIdx > idx+1) )
        {
          spaceIdx--;
        }
        
        var nstr:String = st.substr(0, idx) + st.substr(spaceIdx);
        st = nstr;
      }
      
      return st;
    }
    
        
    
    /**
    * root
    * |
    * +-child1
    * |
    * +-child2
    * |
    * +-child3
    * | |
    * | +child3.1
    * | |child3.2
    * |
    * +-child4
    * */
    public static function traceHierarchy(mc:Sprite):void
    {
      trace("Tracing hierarchy...\n");
      _traceHierarchy(mc);
    }
    
    
    private static function _traceHierarchy(mc:DisplayObjectContainer, level:int = 0):void
    {
      var txtLine:String = "";
      for (var j:int = 0; j < level; j++) txtLine +="    ";
      txtLine += mc.name;
      trace(txtLine);
      
      // If its a movieClip check for labels
      var hmc:MovieClip = mc as MovieClip;
      if (hmc)
      {
        for (i = 0; i < hmc.currentLabels.length; i++)
        {
          trace("" + txtLine + " (MC)-> " + hmc.currentLabels[i].name);
        }
      }
      
      for (var i:int = 0; i < mc.numChildren; i++)
      {
        var cmc:DisplayObjectContainer = mc.getChildAt(i) as DisplayObjectContainer;
        if (cmc) _traceHierarchy(cmc, level+1);      
        else if (mc.getChildAt(i) as TextField)
        {
          trace("" + txtLine + " (TX)-> " + mc.getChildAt(i).name);
        }
        else 
          trace("" + txtLine + " (UO)-> " + "Unrecognized object");
      }      
    }
    
    public static function traceHierarchy2(displayObject:DisplayObjectContainer, deep:int = 0):void
    {
      trace("Tracing " + displayObject.name);
      trace("-----------------------------");
      _traceHierarchy2(displayObject, deep);
      trace("Trace completed");
      trace("-----------------------------");
    }
    
    private static function _traceHierarchy2(displayObject:DisplayObjectContainer, deep:int):void
    {      
      var spaces:String = "";
      for (var i:int = 0; i < deep; i++) spaces += "  ";
      
      for (i = 0; i < displayObject.numChildren; i++)
      {        
        if (displayObject.getChildAt(i) as MovieClip)
        {
          var mc:MovieClip = displayObject.getChildAt(i) as MovieClip;
          var labels:String = "";
          for (var j:int = 0; j < mc.currentLabels.length; j++)
          {
            labels += "|" + mc.currentLabels[j].name + "|";
          }
          trace(spaces + mc.name + "[MC]" + labels);
        }
        else if (displayObject.getChildAt(i) as Sprite)
        {
          trace(spaces + (displayObject.getChildAt(i) as Sprite).name + "[SP]");
        }
        else if (displayObject.getChildAt(i) as DisplayObjectContainer)
        {
          trace(spaces + (displayObject.getChildAt(i) as DisplayObjectContainer).name + "[OC]");
        } 
        else if (displayObject.getChildAt(i) as TextField)
        {
          trace(spaces + (displayObject.getChildAt(i) as TextField).name + "[TF]");
        }  
        else if (displayObject.getChildAt(i) as DisplayObject)
        {
          trace(spaces + (displayObject.getChildAt(i) as DisplayObject).name + "[DO]");
        }
        else
        {
          trace(spaces + "Unknown object");
        }
        
        var dc:DisplayObjectContainer = displayObject.getChildAt(i) as DisplayObjectContainer;
        if (dc) _traceHierarchy2(dc, deep+1);
      }
    }
    
  }
}